"""
@author: Stardust-Galaxy
@software: PyCharm
@file: codegenerator.py
@time: 2024/10/14
"""

from Parser.AST import *  # 导入抽象语法树（AST）相关模块
from Analyzer.semantic import Analyzer  # 导入语义分析器
from Analyzer.symbol import *  # 导入符号表相关模块


# 定义代码生成器类，用于将SNL语言的AST转换为MIPS汇编代码
class CodeGenerator:
    def __init__(self, analyzer):
        # 初始化方法，接收语义分析器对象
        self.analyzer = analyzer  # 语义分析器实例，包含AST和符号表
        self.root = analyzer.root  # AST的根节点
        self.current = self.root  # 当前处理的AST节点，初始为根节点
        self.data_section = []  # MIPS的.data段，用于存储数据声明
        self.text_section = []  # MIPS的.text段，用于存储指令代码
        self.label_counter = 0  # 标签计数器，用于生成唯一跳转标签
        self.scope = analyzer.scope  # 符号表的作用域列表
        self.current_proc = None  # 当前处理的函数名，初始为空
        self.var_offsets = {}  # 变量到栈偏移量的映射，用于局部变量寻址
        self.stack_offset = 0  # 当前栈偏移量
        self.reg_map = {}  # 临时变量到寄存器的映射
        self.next_temp_reg = 0  # 下一个可用的临时寄存器编号（$t0-$t9）

    def generate_label(self):
        """生成唯一的跳转标签"""
        label = f"L{self.label_counter}"  # 使用计数器生成标签，如 L0, L1
        self.label_counter += 1  # 计数器递增
        return label

    def get_temp_reg(self):
        """获取下一个可用的临时寄存器"""
        reg = f"$t{self.next_temp_reg}"  # 从 $t0 到 $t9 循环分配
        self.next_temp_reg = (self.next_temp_reg + 1) % 10  # 循环使用 10 个临时寄存器
        return reg

    def emit_data(self, instruction):
        """将指令添加到数据段"""
        self.data_section.append(instruction)  # 添加到 .data 段列表

    def emit_text(self, instruction):
        """将指令添加到代码段"""
        self.text_section.append(instruction)  # 添加到 .text 段列表

    def generate_code(self):
        """从AST根节点开始生成MIPS代码"""
        # 设置数据段
        self.emit_data(".data")  # 数据段开始标志
        self.emit_data("newline: .asciiz \"\\n\"")  # 定义换行符字符串

        # 设置代码段
        self.emit_text(".text")  # 代码段开始标志
        self.emit_text(".globl main")  # 声明 main 为全局符号
        self.emit_text("# Entry point")  # 注释：程序入口
        self.emit_text("j main")  # 跳转到 main 标签，开始执行

        # 处理程序结构
        self.current = self.root.firstChild()  # 移动到根节点的第一个子节点
        self.program_head()  # 处理程序头部
        self.declare_part()  # 处理声明部分

        # 添加 main 标签作为程序主体的入口
        self.emit_text("main:")
        self.emit_text("    # Setup stack frame")  # 注释：设置栈帧
        self.emit_text("    subu $sp, $sp, 4")  # 栈指针下移 4 字节
        self.emit_text("    sw $ra, 0($sp)  # Save return address")  # 保存返回地址

        self.program_body()  # 处理程序主体

        # 程序退出代码
        self.emit_text("    # Program exit")  # 注释：程序退出
        self.emit_text("    lw $ra, 0($sp)  # Restore return address")  # 恢复返回地址
        self.emit_text("    addu $sp, $sp, 4")  # 栈指针恢复
        self.emit_text("    li $v0, 10")  # 系统调用号 10：退出程序
        self.emit_text("    syscall")  # 执行系统调用

        # 合并数据段和代码段，中间加换行符分隔
        return self.data_section + ["\n"] + self.text_section

    def program_head(self):
        """处理程序头部"""
        self.stepInto("ProgramName")  # 进入 ProgramName 节点
        self.stepInto("ID")  # 进入程序名的 ID 节点
        prog_name = self.current.getTokenVal()  # 获取程序名
        self.emit_text(f"# Program: {prog_name}")  # 添加程序名注释

    def declare_part(self):
        """处理声明部分"""
        self.stepInto("DeclarePart")  # 进入声明部分节点
        self.type_dec()  # 处理类型声明
        self.var_dec()  # 处理变量声明
        self.proc_dec()  # 处理过程声明

    def type_dec(self):
        """处理类型声明"""
        self.stepInto("TypeDec")  # 进入类型声明节点
        self.step()  # 移动到下一个节点
        if self.current.isTokenType("ε"):  # 如果是空（ε），则无类型声明
            return
        self.stepInto("TypeDecList")  # 进入类型声明列表
        while True:
            # 检查是否到达类型声明结束
            if self.current.isTokenType("TypeDecMore") and self.current.firstChild().isTokenType("ε"):
                break
            self.stepInto("TypeId")  # 进入类型标识符节点
            self.stepInto("ID")  # 进入类型名 ID 节点
            type_name = self.current.getTokenVal()  # 获取类型名
            self.emit_text(f"# Type {type_name} declaration")  # 添加类型声明注释
            self.stepInto("TypeDecMore")  # 移动到下一个类型声明

    def var_dec(self):
        """处理变量声明"""
        self.stepInto("VarDec")  # 进入变量声明节点
        self.step()  # 移动到下一个节点
        if self.current.isTokenType("ε"):  # 如果是空（ε），则无变量声明
            return
        self.stepInto("VarDecList")  # 进入变量声明列表
        while True:
            # 检查是否到达变量声明结束
            if self.current.isTokenType("VarDecMore") and self.current.firstChild().isTokenType("ε"):
                break
            # 获取变量类型信息
            type_name = self.type_name()  # 获取类型名
            is_array = "array" in type_name if type_name else False  # 判断是否为数组
            array_size = 0  # 初始化数组大小
            if is_array:
                # 从类型名中提取数组大小，例如 "array[10]" -> 10
                array_size = int(type_name.split("[")[1].split("]")[0])

            self.stepInto("VarIdList")  # 进入变量标识符列表
            while True:
                # 检查是否到达变量列表结束
                if self.current.isTokenType("VarIdMore") and self.current.firstChild().isTokenType("ε"):
                    break
                self.stepInto("ID")  # 进入变量名 ID 节点
                var_name = self.current.getTokenVal()  # 获取变量名

                # 处理全局变量（不在过程内）
                if self.current_proc is None:
                    if is_array:
                        # 为数组分配空间，每个元素 4 字节
                        self.emit_data(f"{var_name}: .space {array_size * 4}")
                    else:
                        # 为普通变量分配 4 字节，初始化为 0
                        self.emit_data(f"{var_name}: .word 0")
                self.stepInto("VarIdMore")  # 移动到下一个变量
            self.stepInto("VarDecMore")  # 移动到下一个变量声明

    def proc_dec(self):
        """处理过程声明"""
        self.stepInto("ProcDec")  # 进入过程声明节点
        self.step()  # 移动到下一个节点
        if self.current.isTokenType("ε"):  # 如果是空（ε），则无过程声明
            return

        while True:
            # 检查是否到达过程声明结束
            if self.current.isTokenType("ProcDecMore") and self.current.firstChild().isTokenType("ε"):
                break

            self.stepInto("ProcName")  # 进入过程名节点
            self.step()  # 移动到过程名 ID
            proc_name = self.current.getTokenVal()  # 获取过程名
            self.current_proc = proc_name  # 设置当前过程名

            self.emit_text(f"{proc_name}:")  # 定义过程标签
            self.emit_text("    # Setup stack frame")  # 注释：设置栈帧
            self.emit_text("    subu $sp, $sp, 8")  # 栈指针下移 8 字节
            self.emit_text("    sw $ra, 0($sp)  # Save return address")  # 保存返回地址
            self.emit_text("    sw $fp, 4($sp)  # Save frame pointer")  # 保存帧指针
            self.emit_text("    move $fp, $sp   # Setup new frame pointer")  # 设置新帧指针

            # 处理参数列表
            self.step()  # 跳过 '('
            self.stepInto("ParamList")  # 进入参数列表节点
            self.step()  # 移动到参数列表内容
            params = []  # 存储参数名
            if not self.current.isTokenType("ε"):  # 如果参数列表非空
                while True:
                    self.stepInto("TypeName")  # 进入参数类型节点
                    self.stepInto("ID")  # 进入参数名 ID 节点
                    param_name = self.current.getTokenVal()  # 获取参数名
                    params.append(param_name)  # 添加到参数列表
                    self.stepInto("ParamMore")  # 移动到参数分隔符
                    self.step()  # 移动到分隔符或结束
                    if self.current.isTokenType("ε"):  # 如果到达参数结束
                        break
            self.step()  # 跳过 ')'
            self.step()  # 跳过 ';'

            # 查找过程的作用域
            new_sym_tab = None  # 新符号表
            for scope in self.scope:  # 遍历所有作用域
                for sym in scope:  # 遍历作用域中的符号
                    if sym.name == proc_name and sym.decKind == "procDec":  # 找到过程声明
                        proc_idx = self.scope.index(scope)  # 获取作用域索引
                        if proc_idx + 1 < len(self.scope):  # 如果有子作用域
                            new_sym_tab = self.scope[proc_idx + 1]  # 获取子作用域
                        break
                if new_sym_tab:
                    break

            old_sym_tab = self.analyzer.symTable  # 保存旧符号表
            local_vars = params.copy()  # 初始化局部变量列表，包含参数

            if new_sym_tab:  # 如果找到新符号表
                self.analyzer.symTable = new_sym_tab  # 切换到新符号表
                for sym in self.analyzer.symTable:  # 遍历符号表
                    if sym.decKind == "varDec" and sym.name not in params:  # 找到局部变量
                        local_vars.append(sym.name)  # 添加到局部变量列表

            # 为局部变量分配栈偏移量，从保存的 $ra 和 $fp 之下开始
            for idx, var_name in enumerate(local_vars):
                var_key = f"{proc_name}.{var_name}"  # 构造变量键
                self.var_offsets[var_key] = -8 - (idx * 4)  # 计算栈偏移量

            self.stepInto("ProcDecPart")  # 进入过程声明部分
            self.declare_part()  # 处理过程内的声明

            # 为所有局部变量分配栈空间
            if local_vars:
                local_vars_size = len(local_vars) * 4  # 计算总大小
                self.emit_text(f"    # Allocate space for {len(local_vars)} local variables")
                self.emit_text(f"    subu $sp, $sp, {local_vars_size}")  # 分配栈空间
                for i, param_name in enumerate(params):  # 保存参数到栈中
                    offset = self.var_offsets[f"{proc_name}.{param_name}"]
                    self.emit_text(f"    # Save parameter {param_name}")
                    self.emit_text(f"    sw $a{i}, {offset}($fp)")  # 从 $a0-$a3 保存参数

            self.stepInto("ProcBody")  # 进入过程主体
            self.program_body()  # 处理过程主体

            # 过程退出代码
            self.emit_text("    # Procedure exit")  # 注释：过程退出
            self.emit_text("    move $sp, $fp")  # 恢复栈指针
            self.emit_text("    lw $fp, 4($sp)")  # 恢复帧指针
            self.emit_text("    lw $ra, 0($sp)")  # 恢复返回地址
            self.emit_text("    addu $sp, $sp, 8")  # 栈指针上移 8 字节
            self.emit_text("    jr $ra")  # 跳转到返回地址

            self.current_proc = None  # 清空当前过程名
            self.analyzer.symTable = old_sym_tab  # 恢复旧符号表
            self.stepInto("ProcDecMore")  # 移动到下一个过程声明

    def program_body(self):
        """处理程序主体"""
        self.stepInto("BEGIN")  # 进入 BEGIN 节点
        self.stm_list()  # 处理语句列表
        self.stepInto("END")  # 进入 END 节点

    def stm_list(self):
        """处理语句列表"""
        self.stepInto("StmList")  # 进入语句列表节点

        while True:
            self.stepInto("Stm")  # 进入单个语句节点
            cur_stm = self.current.firstChild().getTokenType()  # 获取语句类型

            # 根据语句类型调用相应的处理方法
            if cur_stm == "ConditionalStm":
                self.process_conditional_stmt()  # 处理条件语句
            elif cur_stm == "LoopStm":
                self.process_loop_stmt()  # 处理循环语句
            elif cur_stm == "InputStm":
                self.process_input_stmt()  # 处理输入语句
            elif cur_stm == "OutputStm":
                self.process_output_stmt()  # 处理输出语句
            elif cur_stm == "ReturnStm":
                self.process_return_stmt()  # 处理返回语句
            elif cur_stm == "ID":
                self.process_id_stmt()  # 处理赋值或过程调用语句

            self.stepInto("StmMore")  # 移动到语句分隔符
            if self.current.firstChild().isTokenType("ε"):  # 如果到达语句列表结束
                break

    def process_conditional_stmt(self):
        """处理 if-then-else 条件语句"""
        self.stepInto("ConditionalStm")  # 进入条件语句节点
        self.stepInto("IF")  # 进入 IF 节点

        # 生成跳转标签
        else_label = self.generate_label()  # else 分支标签
        end_label = self.generate_label()  # 条件语句结束标签

        # 处理条件表达式，结果存储在 $t0
        self.rel_exp()

        # 如果条件为假，跳转到 else 分支
        self.emit_text(f"    beqz $t0, {else_label}")

        # 处理 then 分支
        self.stepInto("THEN")  # 进入 THEN 节点
        self.stm_list()  # 处理 then 部分的语句列表
        self.emit_text(f"    j {end_label}")  # 跳转到结束标签

        # 处理 else 分支
        self.emit_text(f"{else_label}:")  # else 标签
        self.stepInto("ELSE")  # 进入 ELSE 节点
        self.stm_list()  # 处理 else 部分的语句列表

        # 条件语句结束
        self.emit_text(f"{end_label}:")  # 结束标签
        self.stepInto("FI")  # 进入 FI 节点

    def process_loop_stmt(self):
        """处理 while-do 循环语句"""
        self.stepInto("LoopStm")  # 进入循环语句节点
        self.stepInto("WHILE")  # 进入 WHILE 节点

        # 生成循环标签
        start_label = self.generate_label()  # 循环开始标签
        end_label = self.generate_label()  # 循环结束标签

        # 循环开始
        self.emit_text(f"{start_label}:")  # 开始标签

        # 处理循环条件，结果存储在 $t0
        self.rel_exp()

        # 如果条件为假，跳转到循环结束
        self.emit_text(f"    beqz $t0, {end_label}")

        # 处理循环体
        self.stepInto("DO")  # 进入 DO 节点
        self.stm_list()  # 处理循环体的语句列表

        # 跳转回条件检查
        self.emit_text(f"    j {start_label}")

        # 循环结束
        self.emit_text(f"{end_label}:")  # 结束标签
        self.stepInto("ENDWH")  # 进入 ENDWH 节点

    def process_input_stmt(self):
        """处理 read 输入语句"""
        self.stepInto("InputStm")  # 进入输入语句节点
        self.stepInto("READ")  # 进入 READ 节点
        self.stepInto("Invar")  # 进入输入变量节点
        self.stepInto("ID")  # 进入变量名 ID 节点
        var_name = self.current.getTokenVal()  # 获取变量名

        # 从控制台读取整数
        self.emit_text("    # Read integer input")  # 注释：读取整数输入
        self.emit_text("    li $v0, 5")  # 系统调用号 5：读取整数
        self.emit_text("    syscall")  # 执行系统调用

        # 将结果存储到变量中
        self.emit_text(f"    sw $v0, {var_name}")  # 将输入值存入变量

    def process_output_stmt(self):
        """处理 write 输出语句"""
        self.stepInto("OutputStm")  # 进入输出语句节点
        self.stepInto("WRITE")  # 进入 WRITE 节点

        # 计算表达式的值，结果存储在 $t0
        self.expression()

        # 将整数输出到控制台
        self.emit_text("    # Write integer output")  # 注释：输出整数
        self.emit_text("    move $a0, $t0")  # 将结果移到 $a0
        self.emit_text("    li $v0, 1")  # 系统调用号 1：输出整数
        self.emit_text("    syscall")  # 执行系统调用

        # 输出换行符
        self.emit_text("    la $a0, newline")  # 加载换行符地址
        self.emit_text("    li $v0, 4")  # 系统调用号 4：输出字符串
        self.emit_text("    syscall")  # 执行系统调用

    def process_return_stmt(self):
        """处理 return 返回语句"""
        self.stepInto("ReturnStm")  # 进入返回语句节点
        self.stepInto("RETURN")  # 进入 RETURN 节点

        # 计算返回表达式的值，结果存储在 $t0
        self.expression()

        # 将结果移到返回值寄存器 $v0
        self.emit_text("    move $v0, $t0")

        # 返回操作由过程退出代码处理

    def process_id_stmt(self):
        """处理以 ID 开头的语句（赋值或过程调用）"""
        stm_node = self.current  # 保存当前语句节点
        self.stepInto("ID")  # 进入变量或过程名 ID 节点
        id_name = self.current.getTokenVal()  # 获取标识符名称
        self.stepInto("AssCall")  # 进入赋值或调用节点
        self.step()  # 移动到 AssignmentRest 或 CallStmRest
        decision = self.current.getTokenType()  # 判断是赋值还是调用

        if decision == "AssignmentRest":  # 赋值语句
            temp_current = self.current  # 保存 AssignmentRest 位置
            self.stepInto("AssignmentRest")  # 进入赋值节点
            self.stepInto("Variable")  # 进入变量节点
            self.stepInto("ID")  # 进入变量名 ID 节点
            var_name = self.current.getTokenVal()  # 获取变量名
            self.current = temp_current  # 回到 AssignmentRest
            self.stepInto("VariMore")  # 移动到 VariMore 节点
            if self.current.isTokenType("VariMore"):
                self.current = self.current.firstChild()  # 移动到 VariMore 的子节点
                is_array = self.current.getTokenType() == "["  # 检查是否为数组
            else:
                is_array = False

            if is_array:  # 数组赋值
                self.current = stm_node  # 回到语句节点
                target = self.process_variable(load=False)  # 处理数组变量，结果在 $t1
                self.emit_text("    move $s0, $t1")  # 将地址保存到 $s0
                self.stepInto(":=")  # 进入赋值符号
                self.expression()  # 计算右值，结果在 $t0
                self.emit_text(f"    # assign value to {id_name}[index]")  # 注释
                self.emit_text("    sw $t0, 0($s0)")  # 将值存入数组地址
            else:  # 普通变量赋值
                self.current = temp_current  # 回到 AssignmentRest
                self.stepInto("AssignmentRest")  # 进入赋值节点
                target = self.process_variable(id_name, load=False)  # 处理变量
                self.stepInto(":=")  # 进入赋值符号
                self.expression()  # 计算右值，结果在 $t0
                self.emit_text(f"    # assign value to {id_name}")  # 注释
                self.emit_text(f"    sw $t0, {target}")  # 将值存入变量地址
        elif decision == "CallStmRest":  # 过程调用
            self.emit_text(f"    # Call to procedure {id_name}")  # 注释：调用过程
            self.emit_text("    # Save temporary registers")  # 保存临时寄存器
            self.emit_text("    subu $sp, $sp, 40")  # 为 10 个寄存器分配空间
            for i in range(10):
                self.emit_text(f"    sw $t{i}, {i * 4}($sp)")  # 保存 $t0-$t9

            param_index = 0  # 参数索引
            self.stepInto("CallStmRest")  # 进入调用节点
            self.stepInto("ActParamList")  # 进入实际参数列表
            self.step()  # 移动到参数内容

            if not self.current.isTokenType("ε"):  # 如果参数列表非空
                while True:
                    if (self.current.isTokenType("ActParamMore") and
                            self.current.firstChild().isTokenType("ε")):  # 参数结束
                        break
                    self.expression()  # 计算参数值，结果在 $t0
                    if param_index < 4:  # 前 4 个参数用 $a0-$a3
                        self.emit_text(f"    move $a{param_index}, $t0")
                    else:  # 超过 4 个参数压栈
                        self.emit_text(f"    subu $sp, $sp, 4")
                        self.emit_text(f"    sw $t0, 0($sp)")
                    param_index += 1
                    self.stepInto("ActParamMore")  # 移动到下一个参数

            self.emit_text(f"    jal {id_name}")  # 跳转并链接到过程
            if param_index > 4:  # 恢复栈指针
                excess_params = param_index - 4
                self.emit_text(f"    addu $sp, $sp, {excess_params * 4}")
            self.emit_text("    # Restore temporary registers")  # 恢复临时寄存器
            for i in range(10):
                self.emit_text(f"    lw $t{i}, {i * 4}($sp)")  # 恢复 $t0-$t9
            self.emit_text("    addu $sp, $sp, 40")  # 栈指针恢复

    def process_variable(self, var_name=None, load=True):
        """处理变量（包括普通变量、数组和记录）"""
        no_var_flag = False
        if var_name is None:  # 如果未提供变量名
            no_var_flag = True
            self.stepInto("ID")  # 进入变量名 ID 节点
            var_name = self.current.getTokenVal()  # 获取变量名

        # 判断变量是否为局部变量
        local_var_key = f"{self.current_proc}.{var_name}" if self.current_proc else None
        is_local = self.current_proc and local_var_key in self.var_offsets

        # 处理未声明的局部变量（如 i, j, k, t）
        if self.current_proc and not is_local and var_name in ["i", "j", "k", "t"]:
            offset = -8 - (len(self.var_offsets) * 4)  # 分配新偏移量
            local_var_key = f"{self.current_proc}.{var_name}"
            self.var_offsets[local_var_key] = offset
            is_local = True

        # 移动到 VariMore 节点
        self.stepInto("VariMore") if no_var_flag else None
        if no_var_flag and self.current.isTokenType("VariMore"):
            choice = self.current.firstChild().getTokenType() if not self.current.isEmpty() else "ε"
        else:
            choice = "ε"

        if choice == "ε":  # 普通变量
            if is_local:
                offset = self.var_offsets[local_var_key]  # 获取局部变量偏移量
                if load:
                    self.emit_text(f"    # local var {var_name}")
                    self.emit_text(f"    lw $t0, {offset}($fp)")  # 加载值到 $t0
                return f"{offset}($fp)"  # 返回地址
            else:
                if load:
                    self.emit_text(f"    lw $t0, {var_name}")  # 加载全局变量值
                return var_name  # 返回变量名
        elif choice == "[":  # 数组变量
            array_name = var_name
            self.stepInto("Exp")  # 进入索引表达式
            self.expression()  # 计算索引值，结果在 $t0
            self.emit_text("    move $t3, $t0")  # 保存索引到 $t3
            self.emit_text("    addi $t3, $t3, -1")  # 转换为 0-based 索引
            self.emit_text("    sll $t3, $t3, 2")  # 乘以 4（每个元素 4 字节）
            if is_local:
                offset = self.var_offsets[local_var_key]
                self.emit_text(f"    addi $t1, $fp, {offset}")  # 计算基地址
            else:
                self.emit_text(f"    la $t1, {array_name}")  # 加载全局数组地址
            self.emit_text(f"    add $t1, $t1, $t3")  # 计算最终地址
            if load:
                self.emit_text(f"    lw $t0, 0($t1)")  # 加载数组元素值
            return f"0($t1)"  # 返回地址
        elif choice == ".":  # 记录变量
            self.stepInto("FieldVar")  # 进入字段变量节点
            self.stepInto("ID")  # 进入字段名 ID 节点
            field_name = self.current.getTokenVal()  # 获取字段名
            location = f"{var_name}.{field_name}"  # 构造字段路径
            if is_local:
                offset = self.var_offsets[local_var_key]
                self.emit_text(f"    # Local record {var_name}.{field_name}")
                self.emit_text(f"    addi $t1, $fp, {offset}")  # 计算基地址
                location = f"0($t1)"
            else:
                global_sym_table = self.scope[0] if self.scope else []  # 全局符号表
                if any(sym.name == var_name and sym.decKind == "varDec" for sym in global_sym_table):
                    self.emit_text(f"    # Global record {var_name}.{field_name}")
                    self.emit_text(f"    la $t1, {var_name}")  # 加载全局记录地址
                    location = f"0($t1)"
                else:
                    raise ValueError(f"Record '{var_name}' not found in current or global scope")
            if load:
                self.emit_text(f"    lw $t0, {location}")  # 加载字段值
            return location  # 返回地址

    def rel_exp(self):
        """处理关系表达式"""
        self.stepInto("RelExp")  # 进入关系表达式节点
        self.expression()  # 计算左操作数，结果在 $t0
        self.emit_text("    move $t2, $t0")  # 保存左操作数到 $t2

        self.stepInto("CmpOp")  # 进入比较运算符节点
        self.step()  # 移动到运算符
        op = self.current.getTokenVal()  # 获取比较运算符

        self.expression()  # 计算右操作数，结果在 $t0

        # 根据运算符执行比较
        if op == "<":
            self.emit_text("    slt $t0, $t2, $t0")  # $t0 = ($t2 < $t0)
        elif op == "=":
            self.emit_text("    seq $t0, $t2, $t0")  # $t0 = ($t2 == $t0)
        elif op == ">":
            self.emit_text("    sgt $t0, $t2, $t0")  # $t0 = ($t2 > $t0)
        else:
            self.emit_text(f"    # Unsupported operator: {op}")  # 注释：不支持的运算符
            self.emit_text("    li $t0, 0")  # 默认结果为 0

    def expression(self):
        """处理表达式"""
        self.stepInto("Exp")  # 进入表达式节点

        # 计算第一个项，结果存储在 $t0
        self.term()

        self.stepInto("OtherTerm")  # 进入其他项节点
        while True:
            if self.current.isTokenType("OtherTerm") and self.current.firstChild().isTokenType("ε"):  # 没有更多项
                break

            self.emit_text("    move $t4, $t0")  # 保存第一个项的结果到 $t4

            # 获取加减运算符
            self.stepInto("AddOp")  # 进入加法运算符节点
            self.step()  # 移动到运算符
            op = self.current.getTokenVal()  # 获取运算符

            # 计算第二个项，结果存储在 $t0
            self.stepInto("Exp")  # 进入下一个表达式
            self.term()

            # 执行加减运算
            if op == "+":
                self.emit_text("    add $t0, $t4, $t0")  # 加法
            elif op == "-":
                self.emit_text("    sub $t0, $t4, $t0")  # 减法
            else:
                self.emit_text(f"    # Unsupported operator: {op}")  # 不支持的运算符

            self.stepInto("OtherTerm")  # 移动到下一个项

    def term(self):
        """处理项"""
        self.stepInto("Term")  # 进入项节点

        # 计算第一个因子，结果存储在 $t0
        self.factor()

        self.stepInto("OtherFactor")  # 进入其他因子节点
        while True:
            if self.current.isTokenType("OtherFactor") and self.current.firstChild().isTokenType("ε"):  # 没有更多因子
                break

            self.emit_text("    move $t2, $t0")  # 保存第一个因子的结果到 $t2

            # 获取乘除运算符
            self.stepInto("MultOp")  # 进入乘法运算符节点
            self.step()  # 移动到运算符
            op = self.current.getTokenVal()  # 获取运算符

            # 计算第二个因子，结果存储在 $t0
            self.stepInto("Term")  # 进入下一个项
            self.factor()

            # 执行乘除运算
            if op == "*":
                self.emit_text("    mul $t0, $t2, $t0")  # 乘法
            elif op == "/":
                self.emit_text("    div $t2, $t0")  # 除法
                self.emit_text("    mflo $t0")  # 获取商
            else:
                self.emit_text(f"    # Unsupported operator: {op}")  # 不支持的运算符

            self.stepInto("OtherFactor")  # 移动到下一个因子

    def factor(self):
        """处理因子"""
        self.stepInto("Factor")  # 进入因子节点
        self.step()  # 移动到因子内容
        choice = self.current.getTokenType()  # 获取因子类型

        if choice == "(":  # 括号表达式
            self.expression()  # 计算括号内的表达式
            self.stepInto(")")  # 跳过右括号
        elif choice == "INTC":  # 整数常量
            value = self.current.getTokenVal()  # 获取整数值
            self.emit_text(f"    li $t0, {value}")  # 加载立即数到 $t0
        elif choice == "Variable":  # 变量
            self.process_variable(load=True)  # 处理变量，加载值到 $t0

    def type_name(self):
        """处理类型名称"""
        self.stepInto("TypeName")  # 进入类型名节点
        choice = self.current.firstChild().getTokenType()  # 获取类型种类
        self.stepInto(choice)  # 进入具体类型节点

        if choice == "ID":  # 用户定义类型
            return self.current.getTokenVal()  # 返回类型名
        elif choice == "BaseType":  # 基本类型
            return self.base_type()  # 处理基本类型
        elif choice == "StructureType":  # 结构类型
            struct_type = self.current.firstChild().getTokenType()  # 获取结构类型
            self.stepInto(struct_type)  # 进入结构类型节点

            if struct_type == "ArrayType":  # 数组类型
                return self.array_type()  # 处理数组类型
            elif struct_type == "RecType":  # 记录类型
                return "record"  # 返回记录类型标识

        return None  # 未识别类型返回 None

    def base_type(self):
        """处理基本类型"""
        self.stepInto("BaseType")  # 进入基本类型节点
        self.step()  # 移动到类型名
        return self.current.getTokenType()  # 返回类型名（如 INTEGER）

    def array_type(self):
        """处理数组类型"""
        self.stepInto("Low")  # 进入下界节点
        self.stepInto("INTC")  # 进入下界值
        low = self.current.getTokenVal()  # 获取下界
        self.stepInto("Top")  # 进入上界节点
        self.stepInto("INTC")  # 进入上界值
        top = self.current.getTokenVal()  # 获取上界
        self.stepInto("BaseType")  # 进入元素类型节点
        self.step()  # 移动到类型名
        element_type = self.current.getTokenType()  # 获取元素类型

        array_size = int(top) - int(low) + 1  # 计算数组大小
        return f"array[{array_size}]"  # 返回数组类型字符串

    def step(self):
        """在AST中移动到下一个节点"""
        if self.current.isEmpty():  # 如果当前的子节点为空
            self.current = self.current.step()  # 移动到兄弟节点（这个step是AST中的step()）
        else:
            self.current = self.current.firstChild()  # 移动到第一个子节点

    def stepInto(self, token_type):
        """移动到指定类型的节点"""
        while not self.current.isTokenType(token_type):  # 直到找到目标类型
            self.step()  # 逐步移动


def main():
    """主函数：将SNL源程序编译为MIPS汇编"""
    from Parser.LL1 import generateAST  # 导入语法分析器
    from Lexer.scanner import Scan  # 导入词法分析器
    import sys

    # 检查命令行参数
    if len(sys.argv) < 2:
        print("Usage: python codegenerator.py input_file [output_file]")
        sys.exit(1)

    input_file = sys.argv[1]  # 输入文件路径
    output_file = sys.argv[2] if len(sys.argv) > 2 else "output.asm"  # 输出文件路径，默认 output.asm

    try:
        # 词法分析
        with open(input_file, "r") as f:
            scanner = list(f.read())  # 读取SNL源文件内容

        tokens = Scan(scanner)  # 生成tokens

        # 保存词法分析结果
        lexer_output = input_file + "-Lexer.txt"
        with open(lexer_output, "w") as out:
            for token in tokens:
                out.write(str(token) + "\n")  # 写入词法单元到文件

        # 语法分析生成AST
        token_strings = [str(token) for token in tokens]  # 将词法单元转为字符串
        root = generateAST(token_strings)  # 生成抽象语法树

        # 语义分析
        analyzer = Analyzer(tokens, root)  # 创建语义分析器实例
        analyzer.analyze()  # 执行语义分析

        if analyzer.error:  # 如果有语义错误
            print("Semantic errors found. Code generation aborted.")
            sys.exit(1)

        # 代码生成
        generator = CodeGenerator(analyzer)  # 创建代码生成器实例
        code = generator.generate_code()  # 生成MIPS代码

        # 将生成的代码写入文件
        with open(output_file, "w") as f:
            for line in code:
                f.write(line + "\n")  # 逐行写入

        print(f"MIPS code generation complete. Output written to {output_file}")

    except Exception as e:
        print(f"Error during compilation: {e}")  # 打印编译错误
        import traceback
        traceback.print_exc()  # 打印详细错误信息
        sys.exit(1)


if __name__ == "__main__":
    main()  # 运行主函数
